#pragma once
#include "Rpc_callor.hpp"
#include "Requestor.hpp"
#include "Rpcregistry.hpp"
#include "../Common/Dispatcher.hpp"
#include <unordered_map>
#include "Rpc_topic.hpp"

namespace zgwrpc
{
    namespace client
    {
        // 构建出三种不同的客户端，发现客户端，注册客户端，rpc请求客户端

        // 注册服务端, 向注册中新注册自己的方法
        class ProviderClient
        {
        public:
            using ptr = std::shared_ptr<ProviderClient>;
            ProviderClient(const std::string &ip, int port)
                : _requestor(make_shared<Requestor>()), _provider(make_shared<Provider>(_requestor)), _dispatcher(DispatcherFactory::create())
            {
                auto rsp_callback = std::bind(&zgwrpc::client::Requestor::OnMessage, _requestor.get(), placeholders::_1, placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_callback);
                _client = zgwrpc::ClientFactory::create(port, ip);
                _client->setMessageCallback(bind(&zgwrpc::Dispatcher::dispatch, _dispatcher, placeholders::_1, placeholders::_2));
                _client->connect();
            }

            // 提供服务注册功能
            bool RegistryClient(const std::string &method, const Address &host)
            {
                return _provider->RegistryMethod(_client->connection(), method, host);
            }

        private:
            client::Requestor::ptr _requestor;
            client::Provider::ptr _provider;

            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };

        // 发现服务端-客户端
        class DiscoverClient
        {
        public:
            using ptr = std::shared_ptr<DiscoverClient>;
            DiscoverClient(const std::string ip, int port, Discover::DeleCallback dele_callback)
                : _requestor(make_shared<Requestor>()), _discover(make_shared<Discover>(_requestor, dele_callback)), _dispatcher(DispatcherFactory::create())
            {
                auto rsp_callback = std::bind(&zgwrpc::client::Requestor::OnMessage, _requestor.get(), placeholders::_1, placeholders::_2);
                auto req_callback = std::bind(&Discover::OnServiceRequst, _discover.get(), placeholders::_1, placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_callback);
                _dispatcher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, req_callback);
                _client = zgwrpc::ClientFactory::create(port, ip);
                _client->setMessageCallback(bind(&zgwrpc::Dispatcher::dispatch, _dispatcher, placeholders::_1, placeholders::_2));
                _client->connect();
            }

            // 向外提供服务发现接口
            bool Discoverclient(const std::string &method, Address &host)
            {
                return _discover->ServiceDiscovery(_client->connection(), method, host);
            }

        private:
            client::Requestor::ptr _requestor;
            client::Discover::ptr _discover;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };

        // rpc请求客户端
        class RpcClient
        {
        public:
            // disable_discovery:是否禁用服务发现，决定传入的地址信息时服务注册中心，还是服务提供者的地址
            RpcClient(bool enable_discovery, const std::string &ip, int port)
                : _enable_discovery(enable_discovery), _requestor(std::make_shared<Requestor>()),
                  _rpc_caller(std::make_shared<RpcCaller>(_requestor)),
                  _dispatcher(DispatcherFactory::create())
            {
                auto rsp_callback = std::bind(&zgwrpc::client::Requestor::OnMessage, _requestor.get(), placeholders::_1, placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_RPC, rsp_callback);

                // 如果启用服务发现，则最先创建一个服务发现客户端
                if (_enable_discovery)
                {
                    auto dele_callback = std::bind(&RpcClient::DelClient, this, placeholders::_1);
                    _discover = std::make_shared<DiscoverClient>(ip, port, dele_callback);
                }
                // 如果不启用服务发现，则直接创建一个服务提供者客户端
                else
                {
                    _client = zgwrpc::ClientFactory::create(port, ip);
                    _client->setMessageCallback(bind(&zgwrpc::Dispatcher::dispatch, _dispatcher, placeholders::_1, placeholders::_2));
                    _client->connect();
                }
            }

            bool call(const string &method, const Json::Value &params, Json::Value &result)
            {
                // 如果启用服务发现，则先进行服务发现，获取服务提供者的地址信息
                BaseClient::ptr client = GetClient(method);
                if (client.get() == nullptr)
                    return false;
                return _rpc_caller->call(client->connection(), method, params, result);
            }

            // 异步调用
            bool call(const string &method, const Json::Value &params, std::future<Json::Value> &result)
            {
                BaseClient::ptr client = GetClient(method);
                if (client.get() == nullptr)
                    return false;
                return _rpc_caller->call(client->connection(), method, params, result);
            }
            
            // 异步回调
            bool call(const string &method, const Json::Value &params, const RpcCaller::JsonCallbackResponse &callback)
            {
                BaseClient::ptr client = GetClient(method);
                if (client.get() == nullptr)
                    return false;
                return _rpc_caller->call(client->connection(), method, params, callback);
            }

        private:
            BaseClient::ptr NewClient(const Address &host)
            {
                auto client = zgwrpc::ClientFactory::create(host.second, host.first);
                client->setMessageCallback(bind(&zgwrpc::Dispatcher::dispatch, _dispatcher, placeholders::_1, placeholders::_2));
                client->connect();
                AddClient(host, client);
                return client;
            }

            BaseClient::ptr GetClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _clients.find(host);
                if (it != _clients.end())
                {
                    return it->second;
                }
                return nullptr;
            }

            BaseClient::ptr GetClient(const std::string &method)
            {
                BaseClient::ptr client;
                if (_enable_discovery)
                {
                    // 通过服务发现，获取服务提供者的地址信息
                    // 查看服务提供者是否实例化客户端，有则使用，没有则创建
                    Address host;
                    bool ret = _discover->Discoverclient(method, host);
                    if (ret == false)
                    {
                        LOG(LogLevel::ERROR) << "没有发现到服务提供者";
                        return nullptr;
                    }
                    else
                    {
                        client = GetClient(host);
                        if (client == nullptr)
                        {
                            client = NewClient(host);
                        }
                    }
                }
                else
                {
                    client = _client;
                }
                return client;
            }

            void AddClient(const Address &host, BaseClient::ptr client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.insert(std::make_pair(host, client));
            }
            
            void DelClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients.erase(host);
            }
            
            struct AdressHash
            {
                size_t operator()(const Address &addr) const
                {
                    std::string host = addr.first + std::to_string(addr.second);
                    return std::hash<std::string>{}(host);
                }
            };

            // 内部多了一个服务发现，rpc请求时只能向请求到的主机进行rpc调用
            client::Requestor::ptr _requestor;
            client::DiscoverClient::ptr _discover;
            client::RpcCaller::ptr _rpc_caller;
            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
            bool _enable_discovery;
            std::mutex _mutex;
            std::unordered_map<Address, BaseClient::ptr, AdressHash> _clients; // 根据主机地址，创建的连接池，获取到的客户端地址会最先在此处进行缓存
        };

        class Topic_client
        {
        public:
            Topic_client(const std::string &ip, int port) : _requestor(make_shared<Requestor>()), _dispatcher(DispatcherFactory::create()), _topic_manager(make_shared<TopicManager>(_requestor))
            {
                auto rsp_callback = std::bind(&zgwrpc::client::Requestor::OnMessage, _requestor.get(), placeholders::_1, placeholders::_2);
                _dispatcher->registerHandler<BaseMessage>(MType::RSP_TOPIC, rsp_callback);
                auto req_callback = std::bind(&TopicManager::OnPublishMessage, _topic_manager.get(), placeholders::_1, placeholders::_2);
                _dispatcher->registerHandler<TopicRequest>(MType::REQ_TOPIC, req_callback);
                

                _client = zgwrpc::ClientFactory::create(port, ip); // 服务器的地址
                _client->setMessageCallback(bind(&zgwrpc::Dispatcher::dispatch, _dispatcher, placeholders::_1, placeholders::_2));
                _client->connect();
            }
            bool Create(const std::string &topicname)
            {
                return _topic_manager->Create(_client->connection(),topicname);
            }
            bool Remove(const std::string &topicname)
            {
                return _topic_manager->Remove(_client->connection(), topicname);
            }
            bool Subscribe(const std::string &topicname, const TopicManager::Callback &callback)
            {
                return _topic_manager->Subscribe(_client->connection(), topicname, callback);
            }
            bool Cancel(const std::string &topicname)
            {
                return _topic_manager->Cancel(_client->connection(), topicname);
            }
            bool OnPublish(const std::string &topicname, const std::string &msg)
            {
                return _topic_manager->OnPublish(_client->connection(), topicname, msg);
            }

            void Shutdown()
            {
                _client->shutdown();
            }
            using ptr = std::shared_ptr<Topic_client>;

        private:
            client::Requestor::ptr _requestor;
            TopicManager::ptr _topic_manager;

            Dispatcher::ptr _dispatcher;
            BaseClient::ptr _client;
        };
    }
}
